﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;

namespace Creventive.Wpf.ShellFactory.Utility
{
    /// <summary>
    ///   Provides various helper methods for presentation purposes.
    /// </summary>
    public static class PresentationHelper
    {
        /// <summary>
        ///   Finds the top level object.
        /// </summary>
        /// <param name = "element">The element.</param>
        /// <returns></returns>
        public static DependencyObject FindTopLevelElement(this DependencyObject element)
        {
            DependencyObject current = element;
            DependencyObject parent = null;
            while ((current = current.GetVisualOrLogicalParent()) != null)
                parent = current;
            return parent;
        }

        /// <summary>
        ///   Finds the visual ancestor of the specific type. Does not include the scanned element.
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "element">The element.</param>
        /// <returns></returns>
        public static T FindVisualAncestor<T>(this DependencyObject element) where T : DependencyObject
        {
            return element.FindVisualAncestor(e => e is T) as T;
        }

        /// <summary>
        ///   Finds the visual ancestor matching the given predicate. Does not include the scanned element.
        /// </summary>
        /// <param name = "element">The element.</param>
        /// <param name = "predicate">The predicate.</param>
        /// <returns></returns>
        public static DependencyObject FindVisualAncestor(this DependencyObject element, Func<DependencyObject, bool> predicate)
        {
            var parent = element.GetVisualOrLogicalParent();
            while (parent != null && !predicate.Invoke(parent))
                parent = parent.GetVisualOrLogicalParent();
            return parent;
        }

        /// <summary>
        ///   Tries to retrieve the visual parent of the element. If this fails, the logical parent is retrieved.
        /// </summary>
        /// <param name = "element">The element.</param>
        /// <returns></returns>
        public static DependencyObject GetVisualOrLogicalParent(this DependencyObject element)
        {
            return VisualTreeHelper.GetParent(element) ?? LogicalTreeHelper.GetParent(element);
        }
    }
}